
#ifdef a
//重写：基类中的成员函数必须是虚函数，子类才能对该函数进行重写，否则构成同名隐藏
	//子类对基类虚函数的重写virtual可加可不加，建议加（否则不规范）
	//基类不为虚函数，子类为虚函数，仍旧为同名隐藏
	//子类虚函数必须和基类虚函数的原型一致（返回值类型，参数列表，函数名）
	//两个例外：
		//1.协变
				//基类虚函数返回的必须为"基类"的指针或引用
				//子类虚函数返回的必须为"子类"的指针或引用


#include<iostream>
using namespace std;
class AA {};
class BB : public AA{};

//协变所用
//定义全局函数（用于基类对子类的引用）
AA Aa;
BB Bb;

class A{
public:
	A(int aa = 111)
		:_aa(aa)
	{}
	//基类子类均非虚函数，构成重定义，同名函数隐藏
	void Fun1() {
		cout << "A::Fun1" << endl;
	}
	//基类非虚函数，子类虚函数，重定义
	void Fun2() {
		cout << "A::Fun2" << endl;
	}
	//基类为虚函数，子类非虚函数：重写
	virtual void Fun3() {
		cout << "A::Fun3" << endl;
	}
	//基类,子类均为虚函数：重写
	virtual void Fun4() {
		cout << "A::Fun4" << endl;
	}
	//基类与子类参数列表不同:重定义
	virtual void Fun5() {
		cout << "A::Fun5" << endl;
	}
	//基类与子列返回值不同:重定义
	virtual void Fun6() {
		cout << "A::Fun6" << endl;
	}
	//返回值不同时的两个例外
	//协变
		//基类虚函数返回的必须为"基类"的指针或引用
		//子类虚函数返回的必须为"子类"的指针或引用	
	virtual A* Fun7() {
		cout << "A::Fun7" << endl;
		return this;
	}
	//基类和子类要在一个继承体系内，"基类"和"自类"要在一个继承体系内，但这两个继承体系不一定相同

	//基类与子类返回值类型不同-》但满足协变
	virtual AA& Fun8() {
		cout << "A::Fun8" << endl;
		//Aa为全局对象，若在函数内部定义为临时对象，则返回引用时导致对象失效。
		return Aa;
	}
	
	 ~A() {
		cout << "A::Fun9" << endl;
	}

	 //此处f111(一 一 一)，而子类为 f1l1(一 L 一)，肉眼较难分辨
	 virtual void F1l1() {
		 cout << "A::Fun10" << endl;
	 }

	 // c++11引入override,检查子类某函数是否重写了基类的虚函数，未重写则编译时报错
	 //overried不能用来修饰最上层基类函数，因为基类没有基类；
	 //(11L)
	 virtual void F11l() 
	 {
		 cout << "A:Fun11" << endl;
	 }
	int _aa;
	//override不能修饰子类析构函数，但能修饰协变

	//为了避免无意间的重写，有了final关键字
	//final修饰的类无法被继承
	//final修饰的成员函数不能被子类重写
	//final通常用来修饰子类的函数，而不用来修饰基类函数，修饰后基类将不可重写，无法形成多态，不如直接去掉virtual
	//final不能修饰非虚函数	


	virtual void Fun12() {
		cout << "A::Fun12" << endl;
	}
};

class B : public A
{
public:
	B(int bb = 222)
		:A()
	{}
	void Fun1() {
		cout << "B::Fun1" << endl;
	}
	
	virtual void Fun2() {
		cout << "B::Fun2" << endl;
	}

	void Fun3() {
		cout << "B::Fun3" << endl;
	}
	
	void Fun4() {
		cout << "B::Fun4" << endl;
	}

	void Fun5(int x) {
		cout << "B::Fun5" << endl;
	}

	/*直接报错
	int Fun6() {
		cout << "B::Fun6" << endl;
		return 1;
	}
	*/
	
	B* Fun7()override {
		//通过基类对子类的引用/指针来访问子类的虚函数，其this指针类型为B（B* const）,而不是A&
		cout << "B::Fun7" << endl;
		return this;
		//通过基类对子类的引用或指针来调用虚函数，
	}

	 BB& Fun8()override {
		cout << "B::Fun8" << endl;
		return Bb;
	}
	 ~B() {
		 cout << "B::Fun9" << endl;
	 }

	 void F111()  
	 {
		 cout << "B::Fun10" << endl;
	 }
	 void F11l()override {
		 cout << "B::Fun11" << endl;
	 }

	int _bb;

	//重写与访问权限无关，编译时编译器只会去看声明的类型（A&），依次检查，而不会看其原型(B),而A中Fun12存在且可以访问
	//基类和子类虚函数的访问权限不同--但一般会把基类的虚函数设置为public，基类私有不可类外访问

private: 
	void Fun12()override {
		cout << "B::Fun12" << endl;
	}	
};

void TestFun(A& a) {
	//a.Fun1();
	//a.Fun2();
	//a.Fun3();
	//a.Fun4();
	//a.Fun5();
	//a.Fun6();->直接报错
	//a.Fun7();
	//a.Fun8();
	//a.F1l1();
	a.Fun12();

}
int main() {
	B b;	
	TestFun(b);

	
	/*
	//基类虚函数与子类虚函数的名字不同->析构函数可以重写，第二种例外
	//若不重写，则会导致值释放子类对象中基类的空间而不释放其子类自己的空间
	A* a = new A;
	delete a;

	a = new B;
	delete a;

	return 0;
	*/
}

/*
如果基础类和衍生类定义了相同名称的成员函数，那么通过对象指针调用成员函数时，到底调用那个函数 要根据指针的原型来确定，而不是根据指针实际指向的对象类型确定。

虚拟函数就是为了对“如果你以一个基础类指针指向一个衍生类对象，那么通过该指针，你只能访问基础类定义的成员函数”这条规则反其道而行之的设计。

如果你预期衍生类由可能重新定义一个成员函数，那么你就把它定义成虚拟函数（ virtual ）
*/

#endif 

/*
//重写和重定义的区别

//相同：
	1.都处在继承体系中
	2.都要求函数名相同（重写有例外）

//不同
	1.重写要求函数原型相同
	2.重写要求基类必须为虚函数，重定义不一定
	3.重写只能对函数进行，而重定义也包括变量

*/